#pragma once

#include "localcommon.hpp"

namespace Local_Sock_Mod
{
    // backlog 未完成的订单
    const static int defaultbacklog = 8;
    const static int defaultfd = -1;
    class Socket
    {
    public:
        /***********************禁止拷贝***********************/
        Socket() {}
        virtual ~Socket() {}
        Socket &operator=(const Socket &cpy) = delete;
        Socket(const Socket &cpy) = delete;
        /***********************socket功能函数***********************/
        virtual void SockedCreate() = 0;
        virtual void BindCreate(const uint16_t port) = 0;
        virtual void ListenCreate(const int backlog) = 0;
        virtual std::shared_ptr<Socket> AcceptCreate(Local_Inetaddr::Inetaddr *client) = 0;
        virtual void Close() = 0;
        virtual int Read(std::string *message) = 0;
        virtual int Write(std::string &message) = 0;
        virtual int Recv(std::string *message) = 0;
        virtual int Send(std::string &message) = 0;
        virtual void ConnectCreate(Local_Inetaddr::Inetaddr *server) = 0;
        /***********************socket功能函数***********************/
        void ServerTcpMod(const uint16_t port, const int backlog = defaultbacklog)
        {
            SockedCreate();
            BindCreate(port);
            ListenCreate(backlog);
        }
        void ClientTcpMod()
        {
            SockedCreate();
        }
    };
    class TcpSocket : public Socket
    {

    public:
        /***********************构造析构***********************/
        TcpSocket() : _sockfd(defaultfd) {}
        TcpSocket(int fd) : _sockfd(fd) {}
        ~TcpSocket() {}

        /***********************socket功能函数***********************/
        // override 覆写
        void SockedCreate() override
        {
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LFATAL) << "socket error";
                exit(ERR_SOCKET);
            }
            Local_Log::LOG(Local_Log::LogLever::LINFO) << "socket success ";
        }
        void BindCreate(const uint16_t port) override
        {
            Local_Inetaddr::Inetaddr localaddr(port);
            int ret_bin = ::bind(_sockfd, localaddr.GetAddrPtr(), localaddr.GetAddrSize());
            if (ret_bin < 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LFATAL) << "bind error";
                exit(ERR_BIND);
            }
            Local_Log::LOG(Local_Log::LogLever::LINFO) << "bind success ";
        }
        void ListenCreate(const int backlog) override
        {
            int ret_lis = ::listen(_sockfd, backlog);
            if (ret_lis < 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LFATAL) << "listen error";
                exit(ERR_LISTEN);
            }
            Local_Log::LOG(Local_Log::LogLever::LINFO) << "listen success ";
        }
        std::shared_ptr<Socket> AcceptCreate(Local_Inetaddr::Inetaddr *client) override
        {
            struct sockaddr_in lo_clientaddr;
            socklen_t lo_clientlen = sizeof(lo_clientaddr);
            int ret_acc = accept(_sockfd, (struct sockaddr *)&lo_clientaddr, &lo_clientlen);
            if (ret_acc < 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LFATAL) << "accept error";
                return nullptr;
            }
            client->SetAddr(lo_clientaddr);
            return std::make_shared<TcpSocket>(ret_acc);
        }
        void Close() override
        {
            if (_sockfd > 0)
                ::close(_sockfd);
        }
        int Read(std::string *message) override
        {
            char lo_buffer[1024];
            ssize_t lo_readsize = ::read(_sockfd, lo_buffer, sizeof(lo_buffer) - 1);
            if (lo_readsize > 0)
            {
                lo_buffer[lo_readsize] = 0;
                *message += lo_buffer;
            }
            return lo_readsize;
        }
        int Write(std::string &message) override
        {
            return ::write(_sockfd, message.c_str(), message.size());
        }
        int Recv(std::string *message) override
        {
            char lo_buffer[1024];
            ssize_t lo_readsize = ::recv(_sockfd, lo_buffer, sizeof(lo_buffer) - 1, 0);
            if (lo_readsize > 0)
            {
                lo_buffer[lo_readsize] = 0;
                *message += lo_buffer;
            }
            return lo_readsize;
        }
        int Send(std::string &message) override
        {
            return ::send(_sockfd, message.c_str(), message.size(), 0);
        }
        void ConnectCreate(Local_Inetaddr::Inetaddr *server) override
        {
            int ret_con = ::connect(_sockfd, server->GetAddrPtr(), server->GetAddrSize());
            if (ret_con < 0)
            {
                Local_Log::LOG(Local_Log::LogLever::LFATAL) << "connect error";
                exit(ERR_CONNECT);
            }
            Local_Log::LOG(Local_Log::LogLever::LINFO) << "connect success ";
        }

    private:
        int _sockfd;
    };
}